/*
 * File:   ChessBoard.cpp
 * Author: Michael Ziminsky
 *
 * Created on February 28, 2011, 7:53 PM
 */

#include "ChessBoard.h"
#include "BoardEvent.h"
#include "pieces/King.h"

namespace model
{
    ChessBoard::ChessBoard() : lightTurn(true)
    {
        for (int r = 1; r <= ChessBoard::SIZE; r++)
            for (int c = 0; c < ChessBoard::SIZE; c++)
                grid.insert(std::make_pair(Location(c + 'a', r), globals::cPiece()));
    }

    ChessBoard::ChessBoard(const ChessBoard& orig)// : grid(orig.grid), lightTurn(orig.lightTurn)
    {
        copy(orig);
    }

    ChessBoard& ChessBoard::operator =(const ChessBoard& orig)
    {
//        if (this != &orig)
//        {
//            lightTurn = orig.lightTurn;
//            grid = orig.grid;
//        }
        copy(orig);
        return *this;
    }

    void ChessBoard::copy(const ChessBoard& orig)
    {
        lightTurn = orig.lightTurn;
        grid.insert(orig.grid.cbegin(), orig.grid.cend());
    }

    void ChessBoard::clear()
    {
        lightTurn = true;
        for (const_map_iterator i = grid.cbegin(); i != grid.cend(); i++)
            removePieceAt(i->first);
    }

    void ChessBoard::addBoardListener(const IBoardListener* listener)
    {
        listeners.insert(listener);
    }

    void ChessBoard::removeBoardListener(const IBoardListener* listener)
    {
        listeners.erase(listener);
    }

    void ChessBoard::fireBoardChanged(const Location& loc, const globals::cPiece& value) const
    {
        const BoardEvent event(this, loc, value);
        for (listenerSet::const_iterator i = listeners.begin(); i != listeners.end(); i++)
            (*i)->BoardChanged(event);
    }

    globals::cPiece ChessBoard::setPieceAt(const Location& loc, const globals::cPiece& piece)
    {
        map_iterator i = grid.find(loc);
        globals::cPiece old;
        if (i != grid.end())
        {
            old = i->second;
            i->second = piece;
            if (i->second) i->second->setLocation(&i->first);
            fireBoardChanged(i->first, i->second);
        }
        return old;
    }

    globals::cPiece ChessBoard::removePieceAt(const Location& loc)
    {
        return setPieceAt(loc, globals::cPiece());
    }

    globals::cPiece ChessBoard::movePiece(const Location& from, const Location& to)
    {
        return setPieceAt(to, removePieceAt(from));
    }

    bool ChessBoard::hasLocation(const Location& l) const
    {
        try
        {
            return &grid.at(l);
        }
        catch (std::out_of_range)
        {
            return false;
        }
    }

    const globals::cPiece& ChessBoard::getPieceAt(const Location& l) const
    {
        return grid.at(l);
    }

    void ChessBoard::switchTurn()
    {
        lightTurn = !lightTurn;
    }

    bool ChessBoard::isLightTurn() const
    {
        return lightTurn;
    }

    const ChessBoard::boardMap& ChessBoard::getGrid() const
    {
        return const_cast<const boardMap&>(grid);
    }

    globals::pieceList ChessBoard::getPieces(bool lightTeam) const
    {
        globals::pieceList pieces(new globals::pieceList::element_type);
        for (const_map_iterator i = grid.cbegin(); i != grid.cend(); i++)
            if (i->second && i->second->isLight == lightTeam) pieces->push_back(i->second);
        return pieces;
    }

    const globals::cPiece ChessBoard::getKing(bool lightTeam) const
    {
        for (const_map_iterator i = grid.cbegin(); i != grid.cend(); i++)
            if (i->second && typeid(*(i->second)) == typeid(piece::King) && i->second->isLight == lightTeam) return i->second;
        return globals::cPiece();
    }

} // namespace model
